#include "SyncObject.h"
#include <algorithm> // 包含 std::remove_if

////////////////////////////////////////////////////////////////////////////////////
// _LxObjectWaiter
_LxObjectWaiter::_LxObjectWaiter()
{
	m_bWaitAll = false;
	m_status.firedEvent = -1;
}

_LxObjectWaiter::~_LxObjectWaiter()
{
}

bool _LxObjectWaiter::OnSignaled(int nIndex, bool bManual)
{
	m_mutexcond.LockMutex();

	// 手动对象，无需再检查等状态
	// 自动对象再次检查等待状态，如果已经取消等待，则返回false
	if (!bManual && !m_bWaiting.load(std::memory_order_relaxed))
		return false;

	UnlockedSignalOnce(nIndex);

	m_mutexcond.UnlockMutex();
	return true;
}

int _LxObjectWaiter::Wait(bool bWaitAll, unsigned int dwMilliseconds, _LxWaitObject *pWaitObjects, int count /* = 1 */)
{
	// 填充等待对象
	if (bWaitAll)
		m_status.eventsLeft = count;
	else
		m_status.firedEvent = -1;

	m_bWaitAll = bWaitAll;
	m_bWaiting.store(true, std::memory_order_release);

	bool done = false;
	std::shared_ptr<_LxObjectWaiter> sharedPtr = shared_from_this();

	// 将本Waiter的信息填入等待对象中
	m_mutexcond.LockMutex();
	for (int i = 0; i < count; ++i)
	{
		if (!pWaitObjects[i].PreWait(sharedPtr, i))
			// AddWaiter返回false，表示等待对象已经处于触发状态
			done = UnlockedSignalOnce(i);
	}

	// 初始化返回值
	int result = 0;

	// 计算等待时间点
	timespec ts;
	if (!done)
	{
		if (dwMilliseconds == 0)
		{
			result = WAIT_TIMEOUT;
			done = true;
		}
		else
		{
			ts = pthread_stoptime(ts, dwMilliseconds); // 计算等待时间点
		}
	}

	// 循环等待
	while (!done)
	{
		result = m_mutexcond.UnlockedWait(ts);
		// 当wait不是被唤醒或被中断，则不是超时就是失败，直接退出循环
		if (result != 0 && result != EINTR)
			break;

		// 由于有伪唤醒的情况，所以需要重新检查是否已经等待完毕
		done = (m_bWaitAll && m_status.eventsLeft == 0) ||
			   (!m_bWaitAll && m_status.firedEvent != -1);
	}

	m_bWaiting.store(false, std::memory_order_relaxed);

	for(int i = 0; i < count; ++i)
		pWaitObjects->PostWait(this);

	m_mutexcond.UnlockMutex();

	// 处理返回值，使其于 WindowsAPI 返回一致
	switch (result)
	{
	case 0:
	case EINTR:
		// 如果WaitAll，则返回0. 否则返回触发的信号序号
		result = m_status.firedEvent;
		break;
	case ETIMEDOUT:
		result = WAIT_TIMEOUT;
		break;
	default:
		result = WAIT_FAILED;
	}

	return result;
}

bool _LxObjectWaiter::UnlockedSignalOnce(int nIndex)
{
	// 根据等待类型，设置等待状态
	bool done = false;
	if (m_bWaitAll)
	{
		//
		if (--m_status.eventsLeft == 0)
		{
			done = true;
			m_bWaiting.store(false, std::memory_order_release);
			m_mutexcond.UnlockedSignal();
		}
	}
	else
	{
		done = true;
		m_status.firedEvent = nIndex;
		m_bWaiting.store(false, std::memory_order_release);
		m_mutexcond.UnlockedSignal();
	}

	return done;
}

///////////////////////////////////////////////////////////////////////////////////
// _LxWaitObject
_LxWaitObject::_LxWaitObject()
{
	pthread_mutex_init(&m_mutex, NULL);
}

_LxWaitObject::~_LxWaitObject()
{
	pthread_mutex_destroy(&m_mutex);
}

bool _LxWaitObject::PreWait(std::shared_ptr<_LxObjectWaiter> &prJWaiter, int nWaitIdx)
{
	_SLxWaiter_Info info(prJWaiter, nWaitIdx);
	pthread_mutex_lock(&m_mutex);

	// 清理过期Waiter
	ClearExpireWaiters();

	bool bSignaled = IsSignaled();
	if (bSignaled)
	{
		// 如果已经触发，等同已经被等到
		OnBeWaited();
	}
	else
	{
		// 未触发，记录等待的Waiter信息
		m_waiters.push_back(info);
	}
	pthread_mutex_unlock(&m_mutex);

	return !bSignaled;
}

void _LxWaitObject::PostWait(_LxObjectWaiter *pWaiter)
{
	pthread_mutex_lock(&m_mutex);

	for (auto it = m_waiters.begin(); it != m_waiters.end(); ++it)
	{
		if (it->pJWaiter.get() == pWaiter)
		{
			m_waiters.erase(it);
			break;
		}
	}

	pthread_mutex_unlock(&m_mutex);
}

static bool _RemoveExpiredWaitInfo(_SLxWaiter_Info info)
{
	return !info.pJWaiter->IsWaiting();
}

void _LxWaitObject::ClearExpireWaiters()
{
	m_waiters.erase(
		std::remove_if(m_waiters.begin(), m_waiters.end(), _RemoveExpiredWaitInfo),
		m_waiters.end());
}

//////////////////////////////////////////////////////////////////////////////////////////
// _LxEventObj
_LxEventObj::_LxEventObj(bool bManualReset, bool bInitialSignel)
	: _LxWaitObject()
{
	m_bAutoReset = !bManualReset;
	m_bSignel = bInitialSignel;
}

_LxEventObj::~_LxEventObj() {}

bool _LxEventObj::IsSignaled()
{
	return m_bSignel.load(std::memory_order_relaxed);
}

void _LxEventObj::Signal()
{
	pthread_mutex_lock(&m_mutex);

	if (m_bAutoReset)
	{
		bool done = false;
		while (!done && !m_waiters.empty())
		{
			auto &info = m_waiters.front();

			if (!info.pJWaiter->IsWaiting())
			{
				m_waiters.pop_front();
				continue;
			}

			// 对于自动Event，只要触发一次等待，就退出循环
			done = info.pJWaiter->OnSignaled(info.nWaitIndex, false);
		}

		// 没有有效的Waiter，没有唤醒任何等待，则设置触发状态，
		// 如果已经触发，则由于是自动重置Event，保持未触发状态
		if (!done) 
			m_bSignel.store(true, std::memory_order_release);
	}
	else
	{
		// 手动对象，直接设置触发状态
		m_bSignel.store(true, std::memory_order_release);
		for (size_t i = 0; i < m_waiters.size(); ++i)
		{
			auto &info = m_waiters[i];
			if (!info.pJWaiter->IsWaiting())
				continue;

			info.pJWaiter->OnSignaled(info.nWaitIndex, true);
		}
	}

	pthread_mutex_unlock(&m_mutex);
}

bool _LxEventObj::PreWait(std::shared_ptr<_LxObjectWaiter> &prJWaiter, int nWaitIdx)
{
	// 手动对象，在锁外先判断一下，优化进锁的消耗
	if (!m_bAutoReset && IsSignaled())
		return false;

	return _LxWaitObject::PreWait(prJWaiter, nWaitIdx);
}

void _LxEventObj::OnBeWaited()
{
	if (m_bAutoReset) // 自动重置类型，则重置状态
		m_bSignel.store(false, std::memory_order_release);
}

//////////////////////////////////////////////////////////////////////////////////////////
// _LxSemaphoreObj
_LxSemaphoreObj::_LxSemaphoreObj(int nInitial, int nMax /* = 0 */)
{
	m_nMaxValue = nMax == 0 ? nInitial : nMax;
	m_nValue.store(nInitial, std::memory_order_release);
}
_LxSemaphoreObj::~_LxSemaphoreObj() {}

bool _LxSemaphoreObj::IsSignaled()
{
	return m_nValue.load(std::memory_order_relaxed) > 0;
}

void _LxSemaphoreObj::Signal()
{
	pthread_mutex_lock(&m_mutex);

	bool done = false;
	while (!done && !m_waiters.empty())
	{
		auto &info = m_waiters.front();

		// 绕过waiter的锁，移除过期的Waiter
		if (!info.pJWaiter->IsWaiting())
		{
			m_waiters.pop_front();
			continue;
		}

		done = info.pJWaiter->OnSignaled(info.nWaitIndex, false);
	}

	if (!done)
		m_nValue.store(std::min(m_nMaxValue, m_nValue.load(std::memory_order_relaxed) + 1), std::memory_order_release);

	pthread_mutex_unlock(&m_mutex);
}

void _LxSemaphoreObj::OnBeWaited()
{
	m_nValue.fetch_sub(1, std::memory_order_release);
}
